package com.practice.security.rsa;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.IOException;
import java.security.*;
import java.util.Base64;

public class RSACipher {

	private static final String RSA_CIPHER_NAME = "RSA/ECB/PKCS1Padding";

	public static void main(String[] args) throws IOException {
		
		PublicKey publicKey = RSAKeyPairGenerator.readPublicKey();
		
		PrivateKey privateKey = RSAKeyPairGenerator.readPrivateKey();

		String plainText = "7xb37songa5asi1bcxg";

		String cipherText = encryptText(plainText, publicKey);

		System.out.println(cipherText);

		System.out.println(decryptText(cipherText, privateKey));
		
		String signText = signText(plainText, privateKey);
		
		System.out.println(signText);
		
		System.out.println(verifyText(signText, publicKey));
	}

	public static String encryptText(String plainText, PublicKey publicKey) {

		byte[] plainTextBytes = plainText.getBytes();
		byte[] cipherTextBytes = encrypt(plainTextBytes, publicKey);
		String cipherText = Base64.getEncoder().encodeToString(cipherTextBytes);
		return cipherText;
	}

	private static byte[] encrypt(byte[] plainTextBytes, PublicKey publicKey) {

		byte[] cipherTextBytes = null;
		try {
			Cipher cipher = Cipher.getInstance(RSA_CIPHER_NAME);
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			cipherTextBytes = cipher.doFinal(plainTextBytes);
		} catch (NoSuchAlgorithmException | NoSuchPaddingException
				| InvalidKeyException
				| IllegalBlockSizeException | BadPaddingException e) {
			e.printStackTrace();
		}
		return cipherTextBytes;
	}

	public static String decryptText(String cipherText, PrivateKey privateKey) {

		byte[] cipherTextBytes = Base64.getDecoder().decode(cipherText);
		byte[] plainTextBytes = decrypt(cipherTextBytes, privateKey);
		String plainText = new String(plainTextBytes);
		return plainText;
	}

	private static byte[] decrypt(byte[] cipherTextBytes, PrivateKey privateKey) {

		byte[] plainTextBytes = null;
		try {
			Cipher cipher = Cipher.getInstance(RSA_CIPHER_NAME);
			cipher.init(Cipher.DECRYPT_MODE, privateKey);
			plainTextBytes = cipher.doFinal(cipherTextBytes);
		} catch (NoSuchAlgorithmException | NoSuchPaddingException
				| InvalidKeyException
				| IllegalBlockSizeException | BadPaddingException e) {
			e.printStackTrace();
		}
		return plainTextBytes;
	}
	
	public static String signText(String plainText, PrivateKey privateKey) {
		
		byte[] plainTextBytes = plainText.getBytes();
		byte[] signTextBytes = sign(plainTextBytes, privateKey);
		String signText = Base64.getEncoder().encodeToString(signTextBytes);
		return signText;
	}
	
	private static byte[] sign(byte[] plainTextBytes, PrivateKey privateKey) {
		
		byte[] signTextBytes = null;
		try {
			Cipher cipher = Cipher.getInstance(RSA_CIPHER_NAME);
			cipher.init(Cipher.ENCRYPT_MODE, privateKey);
			signTextBytes = cipher.doFinal(plainTextBytes);
		} catch (NoSuchAlgorithmException | NoSuchPaddingException
				| InvalidKeyException
				| IllegalBlockSizeException | BadPaddingException e) {
			e.printStackTrace();
		}
		return signTextBytes;
	}
	
	public static String verifyText(String signText, PublicKey publicKey) {
		
		byte[] signTextBytes = Base64.getDecoder().decode(signText);
		byte[] plainTextBytes = verify(signTextBytes, publicKey);
		String plainText = new String(plainTextBytes);
		return plainText;
	}
	
	private static byte[] verify(byte[] signTextBytes, PublicKey publicKey) {
		
		byte[] plainTextBytes = null;
		try {
			Cipher cipher = Cipher.getInstance(RSA_CIPHER_NAME);
			cipher.init(Cipher.DECRYPT_MODE, publicKey);
			plainTextBytes = cipher.doFinal(signTextBytes);
		} catch (NoSuchAlgorithmException | NoSuchPaddingException
				| InvalidKeyException
				| IllegalBlockSizeException | BadPaddingException e) {
			e.printStackTrace();
		}
		return plainTextBytes;
	}

}
